Shader "Unlit/Light"
{
    Properties
    {
        _MainColor("MainColor", Color) = (1,1,1,1)
        _SpecularColor("SpecularColor", Color) = (1,1,1,1)
        _SpecularNum("SpecularNum", Range(0, 20)) = 1
    }
    SubShader
    {
        // Base Pass
        Pass
        {
            Tags
            {
                "LightMode"="ForwardBase"
            }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // 用于帮助我们编译所有变体 并且保证衰减相关光照变量能够正确赋值到对应的内置变量中
            #pragma multi_compile_fwdbase

            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            fixed4 _MainColor;
            fixed4 _SpecularColor;
            float _SpecularNum;

            struct v2f
            {
                float4 pos:SV_POSITION;
                float3 wNormal:NORMAL;
                float3 wPos:TEXCOORD0;
            };

            fixed3 getLambertFColor(in float3 wNormal)
            {
                float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                fixed3 color = _LightColor0.rgb * _MainColor.rgb * max(0, dot(wNormal, lightDir));
                return color;
            }

            fixed3 getSpecularColor(in float3 wPos, in float3 wNormal)
            {
                float3 viewDir = normalize(UnityWorldSpaceViewDir(wPos));
                float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                float3 halfA = normalize(viewDir + lightDir);
                fixed3 color = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(wNormal, halfA)), _SpecularNum);
                return color;
            }

            v2f vert(appdata_base v)
            {
                v2f v2fData;
                v2fData.pos = UnityObjectToClipPos(v.vertex);
                v2fData.wNormal = UnityObjectToWorldNormal(v.normal);
                v2fData.wPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                return v2fData;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                fixed3 lambertColor = getLambertFColor(i.wNormal);
                fixed3 specularColor = getSpecularColor(i.wPos, i.wNormal);

                fixed atten = 1;
                fixed3 blinnPhongColor = UNITY_LIGHTMODEL_AMBIENT.rgb + (lambertColor + specularColor) * atten;
                return fixed4(blinnPhongColor.rgb, 1);
            }
            ENDCG
        }


        //Additional Pass 附加渲染通道
        Pass
        {
            Tags
            {
                "LightMode"="ForwardAdd"
            }

            Blend One One

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // 用于帮助我们编译所有变体 并且保证衰减相关光照变量能够正确赋值到对应的内置变量中
            #pragma multi_compile_fwdadd

            #include "UnityCG.cginc"
            #include "Lighting.cginc"


            fixed4 _MainColor;
            fixed4 _SpecularColor;
            float _SpecularNum;


            struct v2f
            {
                float4 pos:SV_POSITION;

                float3 wNormal:NORMAL;

                float3 wPos:TEXCOORD0;
            };

            v2f vert(appdata_base v)
            {
                v2f v2fData;
                //转换模型空间下的顶点到裁剪空间
                v2fData.pos = UnityObjectToClipPos(v.vertex);
                //转换模型空间下的法向量到世界空间
                v2fData.wNormal = UnityObjectToWorldNormal(v.normal);
                //转换模型空间下的顶点到世界空间
                v2fData.wPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                return v2fData;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                fixed3 worldNormal = normalize(i.wNormal);

                // 平行光 光的方向
                #if defined(_DIRECTIONAL_LIGHT)
                    fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                #else
                    // 点光源和聚光灯 光的方向
                    fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.wPos);
                #endif

                // 漫反射
                fixed3 diffuse = _LightColor0.rgb * _MainColor.rgb * max(0, dot(worldNormal, worldLightDir));


                // BlinPhong高光颜色
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.wPos.xyz);
                fixed3 halfDir = normalize(worldLightDir + viewDir);
                fixed3 specular = _LightColor0.rgb * _SpecularColor.rgb * pow(
                    max(0, dot(worldNormal, halfDir)), _SpecularNum);
                

                ////---------------衰减值的计算-----------------------------

                
                #if defined(_DIRECTIONAL_LIGHT)
                    // 平行光
                    fixed atten = 1;
                #elif defined(_POINT_LIGHT)
                    // 点光源
                    float3 lightCoord = mul(unity_WorldToLight, float4(i.wPos, 1)).xyz;
                    fixed atten = tex2D(_LightTexture0, dot(lightCoord,lightCoord).xx).UNITY_ATTEN_CHANNEL;
                #elif defined(_SPOT_LIGHT)
                   // 聚光灯
                    float4 lightCoord = mul(unity_WorldToLight, float4(i.wPos, 1));
                    fixed atten = (lightCoord.z > 0) * 
                                  tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * //cookie上取坐标值（0~1）->光照强度
                                  tex2D(_LightTextureB0, dot(lightCoord,lightCoord).xx).UNITY_ATTEN_CHANNEL; //距离的平方值->衰减因子
                #else
                fixed atten = 1;
                #endif
                //在附加渲染通道中不需要再加上环境光颜色，因为他只需要计算一次 在基础渲染通道中已经计算过了
                return fixed4((diffuse + specular) * atten, 1);
            }
            ENDCG
        }
    }
    Fallback "Specular" 
}